﻿using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.Linq;
using System.Net.Http.Headers;
using System.Net.Security;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace CommonlyUtils
{
    /// <summary>
    /// 由于 HttpWebRequest 不支持并发  封装HttpClient
    /// 时间 20220622
    /// 作者 mrking
    /// </summary>
    public class HttpClientHelper
    {
        #region 预定义方变量
        ////默认的编码
        //private Encoding encoding = Encoding.Default;
        ////Post数据编码
        //private Encoding postencoding = Encoding.Default;

        ////设置本地的出口ip和端口
        //private IPEndPoint _IPEndPoint = null;
        #endregion

        #region 一个HttpClient对象
        //HttpWebRequest对象用来发起请求
        private static HttpClient request_httpclient;
        private static WebProxy request_webProxy;
        private readonly static object _lock = new object();

        /// <summary>
        /// 构造函数 初始化HttpClient 全局一个 支持并发
        /// </summary>
        public HttpClientHelper()
        {
            request_httpclient = GetHttpClient("", 0, false, false);
        }

        /// <summary>
        /// 构造函数 初始化HttpClient 全局一个 支持并发
        /// </summary>
        /// <param name="forcenew">是否强制New新实例</param>
        /// <param name="allowAutoRedirect">是否自动跳转</param>
        public HttpClientHelper(bool forcenew, bool allowAutoRedirect = false)
        {
            request_httpclient = GetHttpClient("", 0, forcenew, allowAutoRedirect);
        }

        /// <summary>
        /// 构造函数 初始化HttpClient 全局一个 支持并发
        /// </summary>
        /// <param name="proxyIp">代理Ip</param>
        /// <param name="port">代理端口</param>
        /// <param name="allowAutoRedirect">是否自动跳转</param>
        public HttpClientHelper(string proxyIp, int port, bool allowAutoRedirect = false)
        {
            request_httpclient = GetHttpClient(proxyIp, port, false, allowAutoRedirect);
        }

        private static HttpClient GetHttpClient(string proxyIp, int port, bool forcenew, bool allowAutoRedirect)
        {
            lock (_lock)
            {
                if (request_httpclient == null || forcenew)
                {
                    var httpHandler = new HttpClientHandler();
                    if (!string.IsNullOrWhiteSpace(proxyIp) && port > 0)
                    {
                        request_webProxy = new WebProxy(proxyIp, port);
                        httpHandler.Proxy = request_webProxy;
                        httpHandler.UseProxy = true;
                        //httpHandler.UseCookies = false;
                    }
                    httpHandler.AllowAutoRedirect = allowAutoRedirect;
                    httpHandler.Credentials = CredentialCache.DefaultCredentials;
                    httpHandler.ServerCertificateCustomValidationCallback = delegate { return true; };
                    request_httpclient = new HttpClient(httpHandler);
                    request_httpclient.Timeout = Timeout.InfiniteTimeSpan;
                }
            }
            return request_httpclient;
        }

        /// <summary>
        /// 更换新的代理Ip 相当于重置HttpClient
        /// </summary>
        /// <param name="webProxy"></param>
        /// <param name="allowAutoRedirect"></param>
        /// <returns></returns>
        private static HttpClient GetNewHttpClient(WebProxy webProxy, bool allowAutoRedirect)
        {
            lock (_lock)
            {
                var httpHandler = new HttpClientHandler();
                request_webProxy = webProxy;
                httpHandler.Proxy = request_webProxy;
                httpHandler.UseProxy = true;
                //httpHandler.UseCookies = false;
                httpHandler.AllowAutoRedirect = allowAutoRedirect;
                httpHandler.Credentials = CredentialCache.DefaultCredentials;
                httpHandler.ServerCertificateCustomValidationCallback = delegate { return true; };
                request_httpclient = new HttpClient(httpHandler);
                request_httpclient.Timeout = Timeout.InfiniteTimeSpan;
                return request_httpclient;
            }
        }

        #endregion

        #region Public

        /// <summary>
        /// 根据相传入的数据，得到相应页面数据
        /// </summary>
        /// <param name="item">参数类对象</param>
        /// <param name="sleepMin">最小间隔时间 单位毫秒 0表示不暂停</param>
        /// <param name="sleepMax">最大间隔时间 单位毫秒</param>
        /// <param name="isCheckHttpStatusCode">是否验证HttpCode状态 默认要验证 非OK的时候直接抛出异常 业务终止</param>
        /// <returns>返回HttpResult类型</returns>
        public HttpResult GetHtml(HttpItem item, int sleepMin = 0, int sleepMax = 0, bool isCheckHttpStatusCode = true)
        {
            return GetHtmlSync(item, sleepMin, sleepMax, isCheckHttpStatusCode).Result;
        }

        /// <summary>
        /// 根据相传入的数据，得到相应页面数据
        /// </summary>
        /// <param name="item">参数类对象</param>
        /// <param name="sleepMin">最小间隔时间 单位毫秒 0表示不暂停</param>
        /// <param name="sleepMax">最大间隔时间 单位毫秒</param>
        /// <param name="isCheckHttpStatusCode">是否验证HttpCode状态 默认要验证 非OK的时候直接抛出异常 业务终止</param>
        /// <returns>返回HttpResult类型</returns>
        public async Task<HttpResult> GetHtmlSync(HttpItem item, int sleepMin = 0, int sleepMax = 0, bool isCheckHttpStatusCode = true)
        {
            #region 判断一下 当前的代理Ip
            if (item.WebProxy != null && request_webProxy?.Address != item.WebProxy.Address)
            {
                request_httpclient = GetNewHttpClient(item.WebProxy, item.Allowautoredirect);
            }
            else if (!string.IsNullOrWhiteSpace(request_webProxy?.Address?.ToString() ?? "") && item.WebProxy == null)
            {
                request_httpclient = GetHttpClient("", 0, true, item.Allowautoredirect);
            }
            #endregion

            //返回参数
            HttpResult result = new HttpResult();

            #region 休眠日志
            if (sleepMin > 0)
            {
                if (sleepMax <= sleepMin)
                {
                    sleepMax = sleepMin + 1;
                }
                await Task.Delay(new Random().Next(sleepMin, sleepMax));
            }
            #endregion

            #region 写日志


            StringBuilder sb = new StringBuilder();
            if (!string.IsNullOrWhiteSpace(item.LogGuid))
            {
                sb.AppendLine($"********** {item.LogGuid} **********");
            }
            if (!string.IsNullOrWhiteSpace(item.ConfigFileName))
            {
                sb.AppendLine($"ConfigFileName：{item.ConfigFileName}");
            }
            sb.AppendLine($"{item.Method} {item.URL}");
            sb.AppendLine($"Webproxy：{request_webProxy?.Address?.ToString() ?? ""}");
            sb.AppendLine($"Body：{item.Postdata}");
            sb.AppendLine($"Cookie：{item.Cookie}");
            sb.AppendLine($"Referer：{item.Referer}");
            sb.AppendLine($"【RequestHeader】");
            sb.AppendLine($"{item.Header?.ToString() ?? ""}");
            #endregion

            try
            {
                var message = new HttpRequestMessage();

                //准备参数
                SetRequest(item, message);

                var response = await request_httpclient.SendAsync(message);

                await GetDataSync(item, response, result);

                #region 日志
                sb.AppendLine($"【RequestMessage.Header】");
                sb.AppendLine($"{response?.RequestMessage?.Headers?.ToString() ?? ""}");
                sb.AppendLine($"Response：StatusCode:{result.StatusCode.GetHashCode()},StatusDescription:{result.StatusDescription}\t{result.RedirectUrl}");
                sb.AppendLine("【ResponseHeader】");
                sb.AppendLine(result.Header?.ToString() ?? "");
                if (item.ResultType == ResultType.String)
                {
                    sb.AppendLine($"【Html】\r\n" + result.Html);
                }
                #endregion

                if (isCheckHttpStatusCode && response != null && !response.IsSuccessStatusCode)
                {
                    sb.AppendLine($"{item.LogGuid}访问异常：{item.Method} {item.URL} {(result.RedirectUrl)}");
                    throw new Exception($"{item.LogGuid}访问异常：{item.Method} {item.URL} {(result.RedirectUrl)}");
                }
            }
            catch (Exception ex)
            {
                result.Html = ex.Message;
                sb.AppendLine("异常:" + ex.Message);
            }
            finally
            {
                if (!string.IsNullOrWhiteSpace(item.LogGuid))
                {
                    sb.AppendLine(item.LogGuid + " end");
                }
                if (item?.IsWriteHttpLog ?? false)
                {
                    LogHelper.WriteLog(sb.ToString());
                }
            }
            if (item.IsToLower) result.Html = result.Html.ToLower();
            return result;
        }
        #endregion

        #region GetData


        /// <summary>
        /// 解密  br 和 gzip
        /// </summary>
        /// <param name="item"></param>
        /// <param name="result"></param>
        /// <param name="resByte"></param>
        /// <returns></returns>
        private byte[] HtmlDecode(HttpItem item, HttpResult result, byte[] resByte)
        {
            var content_Encoding = result.Cookie?.Split(';')?.FirstOrDefault(p => p.StartsWith("Content-Encoding"));
            if (content_Encoding != null)
            {
                content_Encoding = content_Encoding.Split('=').LastOrDefault() ?? null;
            }

            if (item.IsGzip || content_Encoding?.ToLower()?.Trim() == "gzip")
            {
                #region GZIP 解码
                using (var compressStream = new MemoryStream(resByte))
                {
                    using (var zipStream = new GZipStream(compressStream, CompressionMode.Decompress))
                    {
                        using (var resultStream = new MemoryStream())
                        {
                            zipStream.CopyTo(resultStream);
                            return resultStream.ToArray();
                        }
                    }
                }
                #endregion
            }

            return resByte;
        }

        /// <summary>
        /// 获取数据的并解析的方法
        /// </summary>
        /// <param name="item"></param>
        /// <param name="response"></param>
        /// <param name="result"></param>
        private async Task GetDataSync(HttpItem item, HttpResponseMessage response, HttpResult result)
        {
            if (response == null)
            {
                return;
            }
            #region base
            //获取StatusCode
            result.StatusCode = response.StatusCode;
            //获取StatusDescription
            result.StatusDescription = response.StatusCode.ToString();
            //获取Headers
            result.Header = response.Headers;
            //获取最后访问的URl
            result.ResponseUri = response.RequestMessage?.RequestUri?.AbsoluteUri?.ToString() ?? "";
            //重定向的Url
            result.RedirectUrl = response.Headers.Location?.OriginalString ?? "";
            //获取set-cookie
            if (response.Headers.Contains("Set-Cookie"))
            {
                result.Cookie = string.Join(";", response.Headers.GetValues("Set-Cookie").ToList());
            }
            #endregion

            byte[] ResponseByte = await response.Content.ReadAsByteArrayAsync();

            item.IsGzip = response.Content.Headers.ContentEncoding.ToString().Contains("gzip");

            #region byte
            if (ResponseByte != null && ResponseByte.Length > 0)
            {
                //设置编码
                SetEncoding(item, result, ResponseByte);

                //设置返回的Byte
                SetResultByte(item, result, ResponseByte);
            }
            else
            {
                result.Html = string.Empty;
            }
            #endregion

            #region Set Unicode
            try
            {
                if (item.ResultType != ResultType.Byte)
                {
                    //result.Html = Regex.Unescape(result.Html);
                    result.Html = Unicode2String(result.Html);
                }
            }
            catch
            {
            }
            #endregion
        }

        /// <summary>
        /// Unicode转字符串
        /// </summary>
        /// <param name="source">经过Unicode编码的字符串</param>
        /// <returns>正常字符串</returns>
        public string Unicode2String(string source)
        {
            return new Regex(@"\\u([0-9A-F]{4})", RegexOptions.IgnoreCase | RegexOptions.Compiled).Replace(
                         source, x => string.Empty + Convert.ToChar(Convert.ToUInt16(x.Result("$1"), 16)));
        }

        /// <summary>
        /// 设置返回的Byte
        /// </summary>
        /// <param name="item">HttpItem</param>
        /// <param name="result">result</param>
        /// <param name="enByte">byte</param>
        private void SetResultByte(HttpItem item, HttpResult result, byte[] enByte)
        {
            //是否返回Byte类型数据
            if (item.ResultType == ResultType.Byte)
            {
                //Byte数据
                result.ResultByte = enByte;
            }
            else if (item.ResultType == ResultType.String)
            {
                //得到返回的HTML
                result.Html = item.Encoding.GetString(HtmlDecode(item, result, enByte));
            }
            else if (item.ResultType == ResultType.StringByte)
            {
                //Byte数据
                result.ResultByte = enByte;
                //得到返回的HTML
                result.Html = item.Encoding.GetString(HtmlDecode(item, result, enByte));
            }
        }

        /// <summary>
        /// 设置编码
        /// </summary>
        /// <param name="item">HttpItem</param>
        /// <param name="result">HttpResult</param>
        /// <param name="ResponseByte">byte[]</param>
        private void SetEncoding(HttpItem item, HttpResult result, byte[] ResponseByte)
        {
            //是否返回Byte类型数据
            if (item.ResultType == ResultType.Byte)
            {
                result.ResultByte = ResponseByte;
            }
            //从这里开始我们要无视编码了
            if (item.Encoding == null)
            {
                Match meta = Regex.Match(Encoding.Default.GetString(ResponseByte), "<meta[^<]*charset=([^<]*)[\"']", RegexOptions.IgnoreCase);
                string c = string.Empty;
                if (meta != null && meta.Groups.Count > 0)
                {
                    c = meta.Groups[1].Value.ToLower().Trim();
                }
                if (c.Length > 2)
                {
                    try
                    {
                        item.Encoding = Encoding.GetEncoding(c.Replace("\"", string.Empty).Replace("'", "").Replace(";", "").Replace("iso-8859-1", "gbk").Trim());
                    }
                    catch
                    {
                    }
                }
            }
        }

        #endregion

        #region SetRequest

        /// <summary>
        /// 为请求准备参数
        /// </summary>
        ///<param name="item">参数列表</param>
        ///<param name="message">参数列表</param>
        private void SetRequest(HttpItem item, HttpRequestMessage message)
        {
            // 验证证书  目前还没有生效
            SetCer(item);

            message.RequestUri = new Uri(item.URL);

            //设置Header参数
            if (item.Header != null && item.Header.Count > 0)
            {
                foreach (string key in item.Header.AllKeys)
                {
                    message.Headers.TryAddWithoutValidation(key, item.Header[key]);
                    //request_httpclient.DefaultRequestHeaders.Add(key, item.Header[key]);
                }
            }

            if (item.ProtocolVersion != null) message.Version = item.ProtocolVersion;
            //请求方式Get或者Post
            switch (item.Method.ToUpper())
            {
                case "GET": message.Method = HttpMethod.Get; break;
                case "POST": message.Method = HttpMethod.Post; break;
                case "DELETE": message.Method = HttpMethod.Delete; break;
                case "PUT": message.Method = HttpMethod.Put; break;
            }
            if (!string.IsNullOrWhiteSpace(item.UserAgent))
            {
                message.Headers.TryAddWithoutValidation("User-Agent", item.UserAgent);
            }
            if (!string.IsNullOrWhiteSpace(item.Cookie))
            {
                message.Headers.TryAddWithoutValidation("Cookie", item.Cookie);
            }
            if (!string.IsNullOrWhiteSpace(item.Host))
            {
                message.Headers.TryAddWithoutValidation("Host", item.Host);
            }
            if (!string.IsNullOrWhiteSpace(item.Accept))
            {
                message.Headers.TryAddWithoutValidation("Accept", item.Accept);
            }

            if (item.KeepAlive)
            {
                message.Headers.TryAddWithoutValidation("Connection", "keep-alive");
            }

            SetPostData(item, message);
        }

        /// <summary>
        /// 设置证书
        /// </summary>
        /// <param name="item"></param>
        private void SetCer(HttpItem item)
        {
            var handler = new HttpClientHandler();

            if (!string.IsNullOrWhiteSpace(item.CerPath))
            {
                SetCerList(item, handler);
                var certificate = new X509Certificate2(item.CerPath);
                //将证书添加到请求里
                handler.ClientCertificates.Add(certificate);
            }
            else
            {
                //初始化对像，并设置请求的URL地址
                SetCerList(item, handler);
            }
        }
        /// <summary>
        /// 设置多个证书
        /// </summary>
        /// <param name="item"></param>
        private void SetCerList(HttpItem item, HttpClientHandler hander)
        {
            if (item.ClentCertificates != null && item.ClentCertificates.Count > 0)
            {
                foreach (X509Certificate c in item.ClentCertificates)
                {
                    hander.ClientCertificates.Add(c);
                }
            }
        }

        /// <summary>
        /// 设置Post数据
        /// </summary>
        /// <param name="item">Http参数</param>
        private void SetPostData(HttpItem item, HttpRequestMessage message)
        {
            //验证在得到结果时是否有传入数据
            if (!item.Method.Trim().ToLower().Contains("get"))
            {
                if (item.PostEncoding == null)
                {
                    item.PostEncoding = Encoding.UTF8;
                }
                if (!string.IsNullOrWhiteSpace(item.Postdata) && item.PostDataType == PostDataType.String)
                {
                    message.Content = new StringContent(item.Postdata, item.PostEncoding);
                    message.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(item.ContentType);
                }
                else
                {
                    byte[] buffer = null;
                    //写入Byte类型
                    if (item.PostDataType == PostDataType.Byte && item.PostdataByte != null && item.PostdataByte.Length > 0)
                    {
                        //验证在得到结果时是否有传入数据
                        buffer = item.PostdataByte;
                    }//写入文件
                    else if (item.PostDataType == PostDataType.FilePath && !string.IsNullOrWhiteSpace(item.Postdata))
                    {
                        StreamReader r = new StreamReader(item.Postdata, item.PostEncoding);
                        buffer = item.PostEncoding.GetBytes(r.ReadToEnd());
                        r.Close();
                    } //写入字符串
                    else if (!string.IsNullOrWhiteSpace(item.Postdata))
                    {
                        buffer = item.PostEncoding.GetBytes(item.Postdata);
                    }
                    if (buffer != null)
                    {
                        //request.ContentLength = buffer.Length;
                        //request.GetRequestStream().Write(buffer, 0, buffer.Length);

                        //不可能直接创建HttpContent的实例, 而需要去找他的实现类, 经过一番研究, 发现了, 如下四个:
                        //MultipartFormDataContent、FormUrlEncodedContent、StringContent、StreamContent
                        message.Content = new ByteArrayContent(buffer);

                        if (!string.IsNullOrWhiteSpace(item.ContentType))
                        {
                            //message.Content.Headers.ContentType = new MediaTypeHeaderValue(item.ContentType);
                            message.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(item.ContentType);
                            //.Add("Content-Type", item.ContentType);
                        }
                    }
                }
            }
        }

        #endregion

        #region private main
        /// <summary>
        /// 回调验证证书问题
        /// </summary>
        /// <param name="sender">流对象</param>
        /// <param name="certificate">证书</param>
        /// <param name="chain">X509Chain</param>
        /// <param name="errors">SslPolicyErrors</param>
        /// <returns>bool</returns>
        private bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) { return true; }
        #endregion
    }

    #region public class
    /// <summary>
    /// Http请求参考类
    /// </summary>
    public class HttpItem
    {
        /// <summary>
        /// 请求URL必须填写
        /// </summary>
        public string URL { get; set; }
        string _Method = "GET";
        /// <summary>
        /// 请求方式默认为GET方式,当为POST方式时必须设置Postdata的值
        /// </summary>
        public string Method
        {
            get { return _Method; }
            set { _Method = value; }
        }

        /// <summary>
        /// 设置Host的标头信息
        /// </summary>
        public string Host { get; set; }
        Boolean _KeepAlive = true;
        /// <summary>
        ///  获取或设置一个值，该值指示是否与 Internet 资源建立持久性连接默认为true。
        /// </summary>
        public Boolean KeepAlive
        {
            get { return _KeepAlive; }
            set { _KeepAlive = value; }
        }
        string _Accept = "text/html, application/xhtml+xml, */*";
        /// <summary>
        /// 请求标头值 默认为text/html, application/xhtml+xml, */*
        /// </summary>
        public string Accept
        {
            get { return _Accept; }
            set { _Accept = value; }
        }
        string _ContentType = "text/html";
        /// <summary>
        /// 请求返回类型默认 text/html
        /// </summary>
        public string ContentType
        {
            get { return _ContentType; }
            set { _ContentType = value; }
        }
        string _UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)";
        /// <summary>
        /// 客户端访问信息默认Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
        /// </summary>
        public string UserAgent
        {
            get { return _UserAgent; }
            set { _UserAgent = value; }
        }
        /// <summary>
        /// 返回数据编码默认为NUll,可以自动识别,一般为utf-8,gbk,gb2312
        /// </summary>
        public Encoding Encoding { get; set; } = Encoding.UTF8;

        private PostDataType _PostDataType = PostDataType.String;

        /// <summary>
        /// Post的数据类型
        /// </summary>
        public PostDataType PostDataType
        {
            get { return _PostDataType; }
            set { _PostDataType = value; }
        }
        /// <summary>
        /// Post请求时要发送的字符串Post数据
        /// </summary>
        public string Postdata { get; set; }
        /// <summary>
        /// Post请求时要发送的Byte类型的Post数据
        /// </summary>
        public byte[] PostdataByte { get; set; }
        /// <summary>
        /// Cookie对象集合
        /// </summary>
        public CookieCollection CookieCollection { get; set; }
        /// <summary>
        /// 请求时的Cookie
        /// </summary>
        public string Cookie { get; set; }
        /// <summary>
        /// 来源地址，上次访问地址
        /// </summary>
        public string Referer { get; set; }
        /// <summary>
        /// 证书绝对路径
        /// </summary>
        public string CerPath { get; set; }

        /// <summary>
        /// 设置代理对象，不想使用IE默认配置就设置为Null
        /// </summary>
        public WebProxy WebProxy { get; set; }

        private Boolean isToLower = false;
        /// <summary>
        /// 是否设置为全文小写，默认为不转化
        /// </summary>
        public Boolean IsToLower
        {
            get { return isToLower; }
            set { isToLower = value; }
        }

        private Boolean allowautoredirect = false;
        /// <summary>
        /// 支持跳转页面，查询结果将是跳转后的页面，默认是不跳转
        /// </summary>
        public Boolean Allowautoredirect
        {
            get { return allowautoredirect; }
            set { allowautoredirect = value; }
        }

        /// <summary>
        /// 设置返回类型String和Byte
        /// </summary>
        public ResultType ResultType { get; set; } = ResultType.String;

        private WebHeaderCollection header = new WebHeaderCollection();
        /// <summary>
        /// header对象
        /// </summary>
        public WebHeaderCollection Header
        {
            get { return header; }
            set { header = value; }
        }
        /// <summary>
        //     获取或设置用于请求的 HTTP 版本。返回结果:用于请求的 HTTP 版本。默认为 System.Net.HttpVersion.Version11。
        /// </summary>
        public Version ProtocolVersion { get; set; }

        /// <summary>
        /// 设置509证书集合
        /// </summary>
        public X509CertificateCollection ClentCertificates { get; set; }

        /// <summary>
        /// 设置或获取Post参数编码,默认的为Default编码
        /// </summary>
        public Encoding PostEncoding { get; set; }

        private ICredentials _ICredentials = CredentialCache.DefaultCredentials;
        /// <summary>
        /// 获取或设置请求的身份验证信息。
        /// </summary>
        public ICredentials ICredentials
        {
            get { return _ICredentials; }
            set { _ICredentials = value; }
        }

        private Boolean _isGzip = false;
        /// <summary>
        ///  是否执行Gzip解压 默认为否
        /// </summary>
        public Boolean IsGzip
        {
            get { return _isGzip; }
            set { _isGzip = value; }
        }

        private bool _isReset = false;
        /// <summary>
        /// 是否重置request,response的值，默认不重置，当设置为True时request,response将被设置为Null
        /// </summary>
        public bool IsReset
        {
            get { return _isReset; }
            set { _isReset = value; }
        }

        /// <summary>
        /// mrking扩展 20210924
        /// </summary>
        public string LogGuid { get; set; }

        /// <summary>
        /// 配置文件名称 用于记录日志跟踪使用 20210924
        /// </summary>
        public string ConfigFileName { get; set; }

        /// <summary>
        /// 扩展字段1 20210924
        /// </summary>
        public string extend1 { get; set; }

        /// <summary>
        /// 是否自动写Http访问日志
        /// </summary>
        public bool IsWriteHttpLog { get; set; } = false;
    }

    public class HttpResult
    {
        /// <summary>
        /// Http请求返回的Cookie
        /// </summary>
        public string Cookie { get; set; }


        private string _html = string.Empty;
        /// <summary>
        /// 返回的String类型数据 只有ResultType.String时才返回数据，其它情况为空
        /// </summary>
        public string Html
        {
            get { return _html; }
            set { _html = value; }
        }
        /// <summary>
        /// 返回的Byte数组 只有ResultType.Byte时才返回数据，其它情况为空
        /// </summary>
        public byte[] ResultByte { get; set; }
        /// <summary>
        /// header对象
        /// </summary>
        public HttpResponseHeaders Header { get; set; }

        /// <summary>
        /// 返回状态说明
        /// </summary>
        public string StatusDescription { get; set; }

        /// <summary>
        /// 返回状态码,默认为OK
        /// </summary>
        public HttpStatusCode StatusCode { get; set; }

        /// <summary>
        /// 最后访问的URl
        /// </summary>
        public string ResponseUri { get; set; }

        /// <summary>
        /// 获取重定向的URl
        /// </summary>
        public string RedirectUrl { get; set; }
    }

    /// <summary>
    /// Post的数据格式默认为string
    /// </summary>
    public enum PostDataType
    {
        /// <summary>
        /// 字符串类型，这时编码Encoding可不设置
        /// </summary>
        String,
        /// <summary>
        /// Byte类型，需要设置PostdataByte参数的值编码Encoding可设置为空
        /// </summary>
        Byte,
        /// <summary>
        /// 传文件，Postdata必须设置为文件的绝对路径，必须设置Encoding的值
        /// </summary>
        FilePath
    }

    /// <summary>
    /// 返回类型
    /// </summary>
    public enum ResultType
    {
        /// <summary>
        /// 表示只返回字符串 只有Html有数据
        /// </summary>
        String,
        /// <summary>
        /// 表示返回字符串和字节流 ResultByte和Html都有数据返回
        /// </summary>
        Byte,

        /// <summary>
        /// 表示返回字符串和字节流 ResultByte和Html都有数据返回
        /// </summary>
        StringByte
    }
    #endregion
}
